package org.example.async.produceconsume;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

import java.util.LinkedList;

/**
 * @author zhengdp
 * @Description 生产者 消费者模式
 * @Date 2022/10/16 22:33
 * @Created by zhengdp
 */
@Slf4j(topic = "c.ProduceConsumeModel")
public class ProduceConsumeModel {
    public static void main(String[] args) {
        MessageQueue queue = new MessageQueue(2);
        for (int i = 0; i < 3; i++) {
            int id = i;
            new Thread(() -> {
                queue.put(new Message(id,"值"+id));
            },"生产者 "+i).start();
        }

        new Thread(() -> {
            while(true){
                try {
                    Thread.sleep(1000);
                    Message msg = queue.task();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"消费者").start();

    }
}

/**
 *  消息队列类 ， Java线程间通信
 */
@Slf4j(topic = "c.MessageQueue")
class  MessageQueue {

    // 容器，用于存储消息 (消息的队列集合）
    private final LinkedList<Message> list = new LinkedList<>();

    // 队列容量 （消息队列一般有容量限制）
    private final int capacity;

    public MessageQueue(int capacity){
        this.capacity = capacity;
    }

    /**
     * 获取消息
     * @return
     */
    public Message task() {

        // 检查队列是否为空 ==> 为空需要进行等待
        synchronized (list) {
            while(list.isEmpty()){
                try {
                    log.info("队列为空，消费者线程等待");
                    list.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            // 头取 尾放 先进先出
            Message message = list.removeFirst();
            log.info("已消费消息，消息:{}",message);
            // 通知生产者线程
            list.notifyAll();
            return  message;
        }
    }

    public void put(Message msg){
        synchronized (list){
            // 检查队列是否已满 ==> 等待队列有空位
            while(capacity == list.size()){
                try{
                    log.info("队列已满，生产者线程等待");
                    list.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            // 放入数据
            list.addLast(msg);
            log.info("已生产消息，消息:{}",msg);
            // 唤醒消费线程
            list.notifyAll();
        }
    }

}

@Getter
@AllArgsConstructor
@ToString
final class  Message {
    private int id ;
    private Object value;

}
